package com.dh.nio;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;

import org.junit.Test;

import freemarker.ext.beans.MapModel;

/**
 *一 通道源节点与目标节点的链接，在java nio 中负责缓冲区中数据丶存取。本身不存储数据，因此需要配合缓冲区进行传输
 * 
 * 二通道的主要实现类:
 * Java.nio.channels.Channel接口
 *   |--FileChannel 用于本地文件的传输。
 *   |--SocketChannel 用于网络传输
 *   |--ServerSocketChannel 用于网络传输
 *   |--DatagramChannel 用于网络传输
 *   
 * 三如何获取通道
 * 1.Java 针对支持通道的类提供了getChannel()方法
 *       本地IO:
 *       FileInputStream/FileOutputStream
 *       RandomAccessFile
 *       
 *       网络Io
 *       Socket
 *       Serversocket
 *       DatagramSocket
 * 2.在JDK1.7中NIO.2针对各个通道提供了静态方法open()
 * 3.在JDK1.7中NIO.2的Files工具类的newByteChannel()
 * 
 * 四：通道之间传输
 * transferfrom()
 * transferTo()
 * 
 * 五：分散（scatter）于聚集(Gateher)
 * 分散读取(scattering Reads):将通道中的数据分散到多个缓存区中。
 * 聚集写入(Gatehering Writes)：将多个缓存区中的数据写入到通道中。
 * 
 * 六：字符集：Charset
 * 编码：字符串->字节数组
 * 解码：字节数组->字符串
 * 
 * 
 */
public class TestChannel {
	
	@Test
	public void test6() throws Exception{
		Charset cs1=Charset.forName("GBK");
		
		//获取编码器
		CharsetEncoder ce=cs1.newEncoder();
		
		//获取解码器
		CharsetDecoder cd=cs1.newDecoder();
		
		//获取缓冲区
		CharBuffer cBuf=CharBuffer.allocate(1024);
		cBuf.put("你好1234");
		//编码
		cBuf.flip();
		ByteBuffer bBuf=ce.encode(cBuf);
		System.out.println(bBuf.limit());
		System.out.println(bBuf.position());
		//解码；
		CharBuffer cBuf2=cd.decode(bBuf);
		System.out.println(cBuf2.toString());
	}
	
	/*@Test
	public void test5(){
		Map<String,Charset> map =	Charset.availableCharsets();
		Set<Entry<String,Charset>> set=map.entrySet();
		for(Entry<String,Charset> entry:set){
			System.out.println(entry.getKey()+"="+entry.getValue());
		}
	}*/
	
	//利用通道完成文件的复制
	@Test
	public void test1() throws Exception {
		
		FileInputStream fis = new FileInputStream("1.jpg");
		FileOutputStream fos = new FileOutputStream("2.jpg");
		
		//获取通道
		FileChannel inChannel=fis.getChannel();
		FileChannel outChannel=fos.getChannel();
		
		//分配指定大小的缓冲区
		ByteBuffer buf=ByteBuffer.allocate(1024);
		
		//将通道中的数据存入缓冲区
		while(inChannel.read(buf)!=-1) {
			buf.flip();//切换为读模式
			//将缓冲区的数据写入通道
			outChannel.write(buf);
			buf.clear();//清空缓冲区
		}	
	}
	
	/**
	 * 利用直接缓冲完成文件的复制
	 * @throws IOException
	 */
	@Test
	public void test2() throws IOException{
		FileChannel inChannel=FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
		FileChannel outChannel=FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		
		//内存映射文件
		MappedByteBuffer inMappedBuf=inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
		MappedByteBuffer outMappedBuf=outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
		
		//直接对缓冲区进行数据读写操作
		byte[] dst=new byte[inMappedBuf.limit()];
		inMappedBuf.get(dst);
		outMappedBuf.put(dst);
	}
	
	/**
	 *通道之间传输 直接缓存
	 */
	@Test
	public void  test3() throws IOException{
		FileChannel inChannel=FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
		FileChannel outChannel=FileChannel.open(Paths.get("4.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		
		inChannel.transferTo(0, inChannel.size(), outChannel);
		
		inChannel.close();
		outChannel.close();
	}
	
	/**
	 * 分散聚集
	 * @throws IOException 
	 */
	@Test
	public void test4() throws IOException{
		@SuppressWarnings("resource")
		RandomAccessFile raf1=new RandomAccessFile("1.txt", "rw");
		
		//获取通道
		FileChannel channel=raf1.getChannel();
		
		//分配指定大小的缓冲区
		ByteBuffer buf1=ByteBuffer.allocate(100);
		ByteBuffer buf2=ByteBuffer.allocate(1024);
		
		//通道中的数据分散读取到buf1,buf2
		ByteBuffer[] dsts={buf1,buf2};
		channel.read(dsts);
		
		for(ByteBuffer bytebuffer:dsts){
			bytebuffer.flip();
		}
		
		/*byte[] dst=new byte[buf1.limit()];
		System.out.println(dsts[0].get(dst));*/
		//缓冲区转成数组，读0 到limit
		/*System.out.println(new String(dsts[0].array(),"urf-8"));
		System.out.println("-----------------------");
		System.out.println(new String(dsts[1].array(),0,dsts[1].limit()));*/
		
		//聚集写入、
		RandomAccessFile raf2=new RandomAccessFile("2.txt", "rw");
		FileChannel channel2=raf2.getChannel();
		channel2.write(dsts);
	}

}
